#pragma once

#include <algorithm/analytical_model/io/json/converter/shared/data/topology/geometry/AllGeometry.h>

using namespace solar;

void solar::tag_invoke(const boost::json::value_from_tag& tag, boost::json::value& json_value,
                       const std::shared_ptr<Geometry>& geometry)
{
    const auto type = geometry->getType();
    switch (type)
    {
    case GeometryType::kGeometryCylinder:
        return solar::tag_invoke(tag, json_value, *dynamic_cast<const Cylinder*>(geometry.get()));
    case GeometryType::kGeometryCylinder3D:
        return solar::tag_invoke(tag, json_value, *dynamic_cast<const Cylinder3D*>(geometry.get()));
    case GeometryType::kGeometryRectangle:
        return solar::tag_invoke(tag, json_value, *dynamic_cast<const Rectangle*>(geometry.get()));
    case GeometryType::kGeometryRectangle3D:
        return solar::tag_invoke(tag, json_value,
                                 *dynamic_cast<const Rectangle3D*>(geometry.get()));
    }
}

auto solar::tag_invoke(const boost::json::value_to_tag<std::shared_ptr<Geometry>>& /*unused*/,
                       const boost::json::value& json_value) -> std::shared_ptr<Geometry>
{
    const auto* value_ptr = json_value.if_object();
    if (value_ptr == nullptr)
    {
        return {};
    }
    const auto type = io::json::internal::convertGeometryType(json_value.at("type").as_string());
    switch (type)
    {
    case GeometryType::kGeometryCylinder:
        return std::make_shared<Cylinder>(
            solar::tag_invoke(boost::json::value_to_tag<Cylinder>(), json_value));
    case GeometryType::kGeometryCylinder3D:
        return std::make_shared<Cylinder3D>(
            solar::tag_invoke(boost::json::value_to_tag<Cylinder3D>(), json_value));
    case GeometryType::kGeometryRectangle:
        return std::make_shared<Rectangle>(
            solar::tag_invoke(boost::json::value_to_tag<Rectangle>(), json_value));
    case GeometryType::kGeometryRectangle3D:
        return std::make_shared<Rectangle3D>(
            solar::tag_invoke(boost::json::value_to_tag<Rectangle3D>(), json_value));
    }
}
